package ywh.utils
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	import ywh.utils.event.LoadersPoolEvent;
	
	/**
	 * 加载器;
	 * 单例模式;只可以获取最大的
	 *
	 * @author 杨伟华
	 * @version 2.0
	 *
	 * Created 1/20/2013 5:15 PM
	 */
	public class DataLoader extends EventDispatcher
	{
		private var _activeloaders:Vector.<URLLoader>;
		
		private var _usableLoaders:Vector.<URLLoader>;
		
		private var _maxLoaderCount:uint = 1;
		
		private var _loadqueue:Array;
		
		private var _loaderToURLFun:Dictionary;
		
		static private var _$:DataLoader;
		
		public function DataLoader(p:PrivateClass)
		{
			if (!p || _$)
			{
				throw(new Error("DataLoader是一个单例类，请调用DataLoader.$"));
			}
			else
			{
				_$ = this;
			}
			_activeloaders = new Vector.<URLLoader>();
			_usableLoaders = new Vector.<URLLoader>();
			_loadqueue = [];
			_loaderToURLFun = new Dictionary(true);
		}
		
		static private function get $():DataLoader
		{
			return _$ || new DataLoader(new PrivateClass());
		}
		
		static public function get maxLoaderCount():uint
		{
			return $.instanceMaxLoaderCount;
		}
		
		static public function set maxLoaderCount(value:uint):void
		{
			$.instanceMaxLoaderCount = value;
		}
		
		static public function addData(url:String, callBack:Function, target:Object = null, isInsert:Boolean = false, format:String = URLLoaderDataFormat.TEXT):void
		{
			$.addToLoad(url, callBack, target, isInsert, format);
		}
		
		protected function get instanceMaxLoaderCount():uint
		{
			return _maxLoaderCount;
		}
		
		protected function set instanceMaxLoaderCount(value:uint):void
		{
			_maxLoaderCount = value;
		}
		
		protected function addToLoad(url:String, callBack:Function, target:Object = null, isInsert:Boolean = false, format:String = URLLoaderDataFormat.TEXT):void
		{
			_loadqueue[isInsert ? "unshift" : "push"]({"url": url, "callBack": callBack, "format": format, "target": target});
			var loader:URLLoader = getLoader();
			if (loader)
			{
				loadData(loader);
			}
		}
		
		private function makeLoader():URLLoader
		{
			var _urlLoader:URLLoader = new URLLoader();
			_urlLoader.addEventListener(Event.COMPLETE, completeHandler);
			_urlLoader.addEventListener(ProgressEvent.PROGRESS, progressHandler);
			_urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			return _urlLoader;
		}
		
		private function getLoader():URLLoader
		{
			if (_activeloaders.length < _maxLoaderCount)
			{
				var _urlLoader:URLLoader = (_usableLoaders.pop() || makeLoader());
				_activeloaders.push(_urlLoader);
				return _urlLoader;
			}
			else
			{
				return null;
			}
		}
		
		private function completeHandler(event:Event):void
		{
			parseData(event.target as URLLoader);
		}
		
		private function progressHandler(event:ProgressEvent):void
		{
			//trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
		}
		
		private function securityErrorHandler(event:SecurityErrorEvent):void
		{
			parseData(event.target as URLLoader);
		}
		
		private function ioErrorHandler(event:IOErrorEvent):void
		{
			parseData(event.target as URLLoader);
		}
		
		private function parseData(loader:URLLoader):void
		{
			dispatchPoolEvent(LoadersPoolEvent.LOAD_FINISH);
			var URLFunObjext:Object = _loaderToURLFun[loader];
			if (URLFunObjext["target"])
			{
				URLFunObjext["callBack"](loader.data, URLFunObjext["target"])
			}
			else
			{
				URLFunObjext["callBack"](loader.data);
			}
			delete _loaderToURLFun[loader];
			if (_loadqueue.length > 0)
			{
				loadData(loader);
			}
			else
			{
				dispatchPoolEvent(LoadersPoolEvent.LOAD_QUEUE_IS_EMPTY);
				_activeloaders.splice(_activeloaders.indexOf(this), 1);
				_usableLoaders.push(loader);
				if (_activeloaders.length == 0)
				{
					dispatchPoolEvent(LoadersPoolEvent.LOAD_ALL_FINISH);
				}
			}
		}
		
		private function loadData(loader:URLLoader):void
		{
			var info:Object = _loadqueue.shift();
			_loaderToURLFun[loader] = info;
			dispatchPoolEvent(LoadersPoolEvent.LOAD_BEGIN);
			loader.dataFormat = info["format"];
			loader.load(new URLRequest(info["url"]));
		}
		
		private function dispatchPoolEvent(type:String):void
		{
			this.dispatchEvent(new LoadersPoolEvent(type));
		}
	}
}

class PrivateClass
{
}